#pragma once
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


class UdpSvr
{
    public:
        UdpSvr()
        {
            sock_ = -1;
        }
        ~UdpSvr()
        {

        }
        //1.Socket
        bool CreateSocket()
        {
            sock_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if(sock_ < 0)
            {
                perror("socket");
                return false;
            }
            return true;
        }
        //2.Bind
        bool Bind(std::string& ip, uint16_t port)
        {
            struct sockaddr_in addr;
            addr.sin_family = AF_INET;
            addr.sin_port = htons(port);
            //inet_addr:1.将点分十进制的ip转换成uint32 2.将主机字节序转换为网络字节序
            addr.sin_addr.s_addr = inet_addr(ip.c_str());
            int ret = bind(sock_, (struct sockaddr*)&addr, sizeof(addr));
            if(ret < 0)
            {
                perror("bind");
                return false;
            }
            return true;
        }
        //3.Send
        bool Send(std::string& data, struct sockaddr_in* destaddr)
        {
            int sendsize = sendto(sock_, data.c_str(), data.size(), 0, (struct sockaddr*)destaddr, sizeof(struct sockaddr_in));
            if(sendsize < 0)
            {
                perror("sendto");
                return false;
            }
            return true;
        }
        //4.Recv
        //buf : 出参， 返回给调用者接收到了什么数据
        //srcaddr : 这条数据从哪里来的，地址信息是数据源端主机的地址信息
        bool Recv(std::string* buf, struct sockaddr_in* srcaddr)
        {
            char tmp[1024];
            memset(tmp, '\0', sizeof(tmp));
            socklen_t socklen = sizeof(struct sockaddr_in);
            //如果接收缓冲区当中没有数据，且flags为0，则recvfrom会阻塞等待
            int recvsize = recvfrom(sock_, tmp, sizeof(tmp) - 1, 0, (struct sockaddr*)srcaddr, &socklen);
            if(recvsize < 0)
            {
                perror("recvfrom");
                return false;
            }

            (*buf).assign(tmp, recvsize);
            return true;
        }
        //5.Close
        void Close()
        {
            close(sock_);
            sock_ = -1;
        }
    private:
        int sock_;
};
